import UIKit

protocol SomeProtocol {
    var mustBeSettable: Int { get set }
    var doesNeedToBeSettable: Int { get }
}
protocol AnotherPotocol {
    static var someTypeProperty:Int { get set }
}
protocol FullNamed {
    var fullName: String { get }
}
struct Person: FullNamed {
    var fullName: String
}
let john = Person(fullName: "John Appleseed")

class Starship: FullNamed {
    var prefix: String?
    var name: String
    init(prefix: String? = nil, name: String) {
        self.prefix = prefix
        self.name = name		
    }
    
    var fullName: String {
        return (prefix != nil ? prefix! + " " : " ") + name
    }
}

var ncc = Starship(prefix: "USS", name: "Enterprise")
ncc.fullName

//对方法的规定
protocol RandomNumberGenerator1{
    func random() -> Double
}

class LineCongcurGenerator: RandomNumberGenerator1 {
    var lastRandom = 42
    let m = 139968.0
    let a = 3877.0
    let c = 29573.0
        
    func random() -> Double {
        lastRandom = Int((Double(lastRandom) * a + c).truncatingRemainder(dividingBy: m))
        return Double(lastRandom) / m
    }
}


let geeartor = LineCongcurGenerator()
geeartor.random()
geeartor.random()

//异变方法要求
protocol Toggable {
    mutating func toggle()
}

enum OnOffSwitch: Toggable {
    case off, on
    mutating func toggle() {
        switch self {
        case .off:
            self = .on
        case .on:
            self = .off
        }
    }
}
var lightSwitch = OnOffSwitch.off
lightSwitch.toggle()
    

//构造器的要求
//protocol SomeProtocol {
//    init(someParam:Int) {
//        
//    }
//}

//协议作为类型  1.作为函数，方法或构造器中参数类型或返回值类型。2.作为常量变量的类型 3.作为数组，字典或其他元素类型

class Dice {
    let sides: Int
    let gernator: RandomNumberGenerator1
    init(sides: Int, gernator: RandomNumberGenerator1) {
        self.sides = sides
        self.gernator = gernator
    }
    
func roll() -> Int {
        return Int((gernator.random() * Double(sides)) + 1)
    }
}


let d = Dice(sides: 3, gernator: LineCongcurGenerator())
for _ in 1...5 {
    print("radmon dice roll is \(d.roll())")
}

//委托
protocol DiceGame {
    var dice: Dice { get }
    func play()
}

protocol DiceGameDelegate {
    func gameDidStart(_ game:DiceGame)
    func game(_ geme: DiceGame, didStartNewTurn diceRoll: Int)
    func gameDidEnd(_ game:DiceGame)
}


class SnakeAndLadder: DiceGame {
    let finalSquare = 25
    var dice = Dice(sides: 6, gernator: LineCongcurGenerator())
    var square = 0
    var board = [Int]()

    init() {
        board = Array(repeating: 0, count: finalSquare + 1)
        board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
               board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
    }
     var delegate:DiceGameDelegate?
    
    func play() {
        square = 0
        delegate?.gameDidStart(self)
        
        gameLoop:while square != finalSquare {
            let diceRoll = dice.roll()
            delegate?.game(self, didStartNewTurn: diceRoll)
            switch square + diceRoll {
            case finalSquare:
                break gameLoop
            case let newSquare where  newSquare > finalSquare:
                continue gameLoop
            default:
                square += diceRoll
                square += board[square]
            }
        }
        
        delegate?.gameDidEnd(self)
  }
    
}

class DiceGameTracker:  DiceGameDelegate
{
    var numberOfTurns = 0
    func gameDidStart(_ game: DiceGame) {
        numberOfTurns = 0
        if game is SnakeAndLadder {
            print("Started a new game of Snakes and Ladders")
        }
        
        print("The game is using a \(game.dice.sides)-sided dice")
    }
    
    func game(_ geme: DiceGame, didStartNewTurn diceRoll: Int) {
        numberOfTurns += 1
        print("Rolled a \(diceRoll)")
    }
    
    func gameDidEnd(_ game: DiceGame) {
        print("The game lasted for \(numberOfTurns) turns")
    }

}


let games = SnakeAndLadder()
let tracker = DiceGameTracker()

games.delegate = tracker
games.play()


//在扩展中使用协议
protocol TextRepresentation {
    var textualDescription: String { get }
}

extension Dice: TextRepresentation { //现在所有的Dice的实例都可以看做TextRepresentation类型
    var textualDescription: String {
        return "A \(sides)-siede dice"
    }
}

let d12 = Dice(sides: 12, gernator: LineCongcurGenerator())
print(d12.textualDescription)

//有条件的遵循协议
extension Array : TextRepresentation where Element : TextRepresentation {
    var textualDescription: String {
        let itemAsText = self.map { $0.textualDescription }
        return "[" + itemAsText.joined(separator: ",") + "]"
    }
}

let textArray =  [d12]
textArray[0].textualDescription

let str: String = "abc"

//显式的遵循协议
struct Hamster {
    var name: String
    var textualDescription: String {
        return "A hamster name: \(name)"
    }
}

extension Hamster: TextRepresentation {}
let simonHamster = Hamster(name: "simon")
let someTextRepresention: TextRepresentation = simonHamster

//合成实现采纳协议
struct Vector3D: Equatable {
    var x = 0.0, y = 0.0, z = 0.0
}
let v1 = Vector3D(x: 2.0, y:3.0, z: 4.0)
let v2 = Vector3D(x: 2.0, y:3.0, z: 4.0)
if v1 == v2 {
    print("v1 is equal to v2")
}

/**
 在包含类型原始声明的文件中声明对 Hashable 协议的遵循，可以得到 hash(into:) 的合成实现，且无需自己编写任何关于 hash(into:) 的实现代码。

 Swift 为没有原始值的枚举类型提供了 Comparable 协议的合成实现。如果枚举类型包含关联类型，那这些关联类型也必须同时遵循 Comparable 协议。在包含原始枚举类型声明的文件中声明其对 Comparable 协议的遵循，可以得到 < 操作符的合成实现，且无需自己编写任何关于 < 的实现代码。Comparable 协议同时包含 <=、> 和 >= 操作符的默认实现。
 */

enum SkillLevel: Comparable {
    case beginer
    case intermedia
    case expert(stars: Int)
}
var levels = [SkillLevel.intermedia,  SkillLevel.beginer,
              SkillLevel.expert(stars: 5), SkillLevel.expert(stars: 3)]
for level in levels.sorted() { //比较之后
    print(level)
}

//协议类型的集合
let athings : [TextRepresentation] = [d12, simonHamster]
for thing in athings {
    print(thing.textualDescription)
}
//协议的继承
/**
 protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
     // 这里是协议的定义部分
 }
 */

protocol PrettyTextRepresentation : TextRepresentation {
    var prettyTextualDescription: String { get }
}

extension SnakeAndLadder : PrettyTextRepresentation {
    var textualDescription: String {
        return "this is textual description"
    }
    
    var prettyTextualDescription: String {
        var output = textualDescription + ":\n"
        for index in 1...finalSquare {
            switch board[index] {
            case let laddr where laddr > 0:
                output += "红三角形 "
                break
            case let snake where snake < 0:
                output += "红五角星 "
                break
        
            default:
                output += "圆圈 "
            }
        }
        
        return output
    }
}
print(games.prettyTextualDescription)

/**
 你通过添加 AnyObject 关键字到协议的继承列表，就可以限制协议只能被类类型遵循（而不能是结构体类型或者枚举类型）。
 */

protocol SomePro: AnyObject {
    
}

//struct aStruct : SomePro {
//    
//}
//Non-class type 'aStruct' cannot conform to class protocol 'SomePro'

//协议合成 协议组合使用 SomeProtocol & AnotherProtocol 的形式。你可以列举任意数量的协议，用和符号（&）分开。除了协议列表，协议组合也能包含类类型，这允许你标明一个需要的父类。

protocol Named {
    var name:String { get }
}
protocol Aged {
    var age:Int { get }
}

struct PPerson: Named, Aged {
    var name:String
    var age:Int
}

func wishHappyBirthday(to celebrate: Named & Aged) {
    print("Happy birthday, \(celebrate.name), you're \(celebrate.age)")
}

let lxy = PPerson(name: "lxy", age: 22)
wishHappyBirthday(to: lxy)
//wishHappyBirthday(to:) 函数的参数 celebrator 的类型为 Named & Aged， 这意味着“任何同时遵循 Named 和 Aged 的协议”。它不关心参数的具体类型，只要参数遵循这两个协议即可。
class Location {
    var lattitude: Double
    var longtitude: Double
    init(lattitude: Double, longtitude: Double) {
        self.lattitude = lattitude
        self.longtitude = longtitude
    }
}
class City: Location, Named {
    var name: String
    init(name: String, lat: Double, longt: Double) {
      
        self.name = name
        super.init(lattitude:lat, longtitude: longt)
    }
}

func beginConcet(in location:Location & Named) -> Void {
    print("hello, \(location.name)")
}

//beginConcert(in:) 函数接受一个类型为 Location & Named 的参数，这意味着“任何 Location 的子类，并且遵循 Named 协议”。在这个例子中，City 就满足这样的条件。
let city = City(name: "guangzhou", lat: 102.9121, longt: 83.112)
beginConcet(in: city)

/**
 你可以使用 类型转换 中描述的 is 和 as 操作符来检查协议一致性，即是否遵循某协议，并且可以转换到指定的协议类型。检查和转换协议的语法与检查和转换类型是完全一样的：

 is 用来检查实例是否遵循某个协议，若遵循则返回 true，否则返回 false；
 as? 返回一个可选值，当实例遵循某个协议时，返回类型为协议类型的可选值，否则返回 nil；
 as! 将实例强制向下转换到某个协议类型，如果强转失败，将触发运行时错误。
 */

protocol HasArea {
    var area: Double { get }
}
class Circle : HasArea {
    let pi = 3.1415926
    var raduis: Double
    var area: Double {
        return pi * raduis * raduis
    }
    init(raduis: Double) {
        self.raduis = raduis
    }
}
class Country : HasArea {
    var area: Double
    init(area: Double) {
        self.area = area
   }
}
class Animal {
    let legs: Int
    init(legs: Int) {
        self.legs = legs
    }
}

let objects:[AnyObject] = [Circle(raduis: 2.0),
                          Country(area: 243_610),
                        Animal(legs: 4)]
                     
for ani in objects {
    if let animal = ani as? HasArea {
        print("area is \(animal.area)")
    } else {
        print("Something that doesn't have an area")
    }
}
 
//可选的协议要求
//在协议中使用 optional 关键字作为前缀来定义可选要求。可选要求用在你需要和 Objective-C 打交道的代码中。协议和可选要求都必须带上 @objc 属性。标记 @objc 特性的协议只能被继承自 Objective-C 类的类或者 @objc 类遵循，其他类以及结构体和枚举均不能遵循这种协议。

@objc protocol CounterDataSource {
    @objc optional func increment(forCount count:Int) -> Int
    @objc optional var fixedIncrement:Int { get }
}

class Counter: CounterDataSource {
    var count:Int = 0
    var dataSource:CounterDataSource?
    func increment() {
        if let amount = dataSource?.increment?(forCount: count) {
            count += amount
        } else if let amount = dataSource?.fixedIncrement {
            count += amount
        }
    }
}
class ThreeSource:NSObject, CounterDataSource {
    let fixedIncrement = 3
}

var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
    counter.increment()
    print(counter.count)
}

class TowardZeroSoucre: NSObject, CounterDataSource {
    func increment(forCount count: Int) -> Int {
        if count == 0 {
            return 0
        } else if count < 0 {
            return 1
        } else {
            return -1
        }
    }
}

counter.count = -4
counter.dataSource = TowardZeroSoucre()
for _ in 1...5 {
    counter.increment()
    print(counter.count)
}

//协议扩展
//协议可以通过扩展来为遵循协议的类型提供属性、方法以及下标的实现。通过这种方式，你可以基于协议本身来实现这些功能，而无需在每个遵循协议的类型中都重复同样的实现，也无需使用全局函数。

extension RandomNumberGenerator1 {
    func randomBool() -> Bool {
        return random() > 0.5
    }
}

let aaa = LineCongcurGenerator()
print("Here is a random number : \(aaa.random())")
print("and here is a random bool: \(aaa.randomBool())")

//为协议扩展添加限制条件
//在扩展协议的时候，可以指定一些限制条件，只有遵循协议的类型满足这些限制条件时，才能获得协议扩展提供的默认实现。这些限制条件写在协议名之后，使用 where 子句来描述，正如 泛型 Where 子句 中所描述的。


extension Collection where Element:Equatable {
    func allEqual() -> Bool {
        for elment in self {
            if elment != self.first {
                return false
            }
        }
        return true
    }
}
//如果集合中的所有元素都一致，allEqual() 方法才返回 true。

let arr1 = [100,100,100,100]
arr1.allEqual() //true
let arr2 = [100,200,100,100]
arr1.allEqual() //false
